# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: api\filters\__init__.py
__author__ = "sanyi"
from typing import Union
from collections import defaultdict
from urllib.parse import unquote as urllib_parse_unquote
from uuid import UUID
import dateutil.parser as dateutil_parser
from server.http_responses.http_errors import InvalidFilter


class Filters:
    def __init__(self, descriptor, filter_string=None):
        self.descriptor = descriptor
        self.data = dict()
        if filter_string:
            self.feed(filter_string)

    def get_key_info(self, key):
        return self.descriptor[key]

    def __parse_expression(self, key, value, operator="eq"):
        expression_descriptor = self.descriptor["keys"].get(key, None)
        if expression_descriptor is None:
            raise InvalidFilter(key, "Unknown filter key")
        value_type = expression_descriptor["value_type"]
        allowed_values = expression_descriptor.get("allowed_values", None)
        if value is None:
            if value_type is not None:
                raise InvalidFilter(key, "Invalid value format")
            self.data[key].append(("eq", (None,)))
            return
        if value.startswith("="):
            operator = "eq"
            value = value[1:]
        else:
            if value.startswith(">="):
                operator = "ge"
                value = value[2:]
            else:
                if value.startswith(">"):
                    operator = "gt"
                    value = value[1:]
                else:
                    if value.startswith("<="):
                        operator = "le"
                        value = value[2:]
                    else:
                        if value.startswith("<"):
                            operator = "lt"
                            value = value[1:]
                        else:
                            if value.startswith("!="):
                                operator = "ne"
                                value = value[2:]
                            else:
                                if value.startswith("!"):
                                    operator = "ne"
                                    value = value[1:]
                                else:
                                    if value.startswith("*"):
                                        operator = "ilike_op"
                                        value = value[1:]
                                if operator not in expression_descriptor.get(
                                    "operators", ("eq",)
                                ):
                                    raise InvalidFilter(key, "Invalid operator")
                                multiple_values_allowed = expression_descriptor.get(
                                    "multiple_values", False
                                )
                                if multiple_values_allowed:
                                    values = value.split(",")
                                else:
                                    values = (value,)
                                cured_values = []
                                value_type = expression_descriptor["value_type"]
                                for value in values:
                                    value = urllib_parse_unquote(value)
                                    value = value.strip()
                                    if not value:
                                        continue
                                    if value_type is None:
                                        cured_values.append(None)
                                    elif value_type == "date":
                                        if len(value) > 50:
                                            raise InvalidFilter(key, "Invalid datetime")
                                        try:
                                            value = dateutil_parser.parse(value)
                                        except ValueError:
                                            raise InvalidFilter(key, "Invalid datetime")

                                        cured_values.append(value)
                                    elif value_type in ("int", "integer"):
                                        if len(value) > 50:
                                            raise InvalidFilter(
                                                key, "Invalid int value"
                                            )
                                        try:
                                            value = int(value)
                                        except ValueError:
                                            raise InvalidFilter(
                                                key, "Invalid int value"
                                            )

                                        if allowed_values is not None:
                                            if value not in allowed_values:
                                                raise InvalidFilter(
                                                    key, "Value not allowed"
                                                )
                                        min_value = expression_descriptor.get(
                                            "min_value", None
                                        )
                                        max_value = expression_descriptor.get(
                                            "max_value", None
                                        )
                                        if min_value is not None:
                                            if value < min_value:
                                                raise InvalidFilter(key, "Out of range")
                                        if max_value is not None:
                                            if value > max_value:
                                                raise InvalidFilter(key, "Out of range")
                                        cured_values.append(value)
                                    elif value_type == "float":
                                        if len(value) > 50:
                                            raise InvalidFilter(
                                                key, "Invalid float value"
                                            )
                                        try:
                                            value = float(value)
                                        except ValueError:
                                            raise InvalidFilter(
                                                key, "Invalid float value"
                                            )

                                        if allowed_values is not None:
                                            if value not in allowed_values:
                                                raise InvalidFilter(
                                                    key, "Value not allowed"
                                                )
                                        min_value = expression_descriptor.get(
                                            "min_value", None
                                        )
                                        max_value = expression_descriptor.get(
                                            "max_value", None
                                        )
                                        if min_value is not None:
                                            if value < min_value:
                                                raise InvalidFilter(key, "Out of range")
                                        if max_value is not None:
                                            if value > max_value:
                                                raise InvalidFilter(key, "Out of range")
                                        cured_values.append(value)
                                    elif value_type in ("bool", "boolean"):
                                        if len(value) > 10:
                                            raise InvalidFilter(
                                                key, "Invalid boolean value"
                                            )
                                        value = value.lower()
                                        if value in ("0", "no", "false"):
                                            cured_values.append(False)
                                        else:
                                            if value in ("1", "yes", "true"):
                                                cured_values.append(True)
                                    else:
                                        if value_type == "string":
                                            if allowed_values is not None:
                                                if value not in allowed_values:
                                                    raise InvalidFilter(
                                                        key, "Value not allowed"
                                                    )
                                            value_len = len(value_type)
                                            min_len = expression_descriptor.get(
                                                "min_len", None
                                            )
                                            max_len = expression_descriptor.get(
                                                "max_len", None
                                            )
                                            if min_len is not None:
                                                if value_len < min_len:
                                                    raise InvalidFilter(
                                                        key,
                                                        "String length out of range",
                                                    )
                                            if max_len is not None:
                                                if value_len > max_len:
                                                    raise InvalidFilter(
                                                        key,
                                                        "String length out of range",
                                                    )
                                            string_conversion = expression_descriptor.get(
                                                "string_conversion", None
                                            )
                                            if string_conversion:
                                                value = string_conversion.get(
                                                    value, value
                                                )
                                            cured_values.append(value)
                                        else:
                                            if value_type == "uuid4":
                                                if 32 > len(value) > 36:
                                                    raise InvalidFilter(
                                                        key, "Invalid UUID"
                                                    )
                                                if allowed_values is not None:
                                                    if value not in allowed_values:
                                                        raise InvalidFilter(
                                                            key, "Value not allowed"
                                                        )
                                                try:
                                                    UUID(value, version=4)
                                                    cured_values.append(value)
                                                except ValueError:
                                                    raise InvalidFilter(
                                                        key, "Invalid UUID"
                                                    )

                                            else:
                                                raise InvalidFilter(key, "Invalid type")

                                self.data[key].append((operator, cured_values))

    def feed(self, search_string):
        self.data = defaultdict(list)
        and_expressions_str_list = search_string.split(";")
        for expression_str in and_expressions_str_list:
            expression_str = expression_str.strip()
            if not expression_str:
                continue
            expression_parts = expression_str.split(":", 1)
            expression_parts_len = len(expression_parts)
            if expression_parts_len == 1:
                key = expression_parts[0].strip()
                if key in self.descriptor["keys"]:
                    self._Filters__parse_expression(key, None)
                else:
                    default = self.descriptor.get("default")
                    if default is None:
                        raise InvalidFilter(key, "no default filter")
                    self._Filters__parse_expression(
                        default["key"], key, operator=default["operator"]
                    )
            elif expression_parts_len == 2:
                self._Filters__parse_expression(
                    expression_parts[0].strip(), expression_parts[1].strip()
                )
            else:
                raise InvalidFilter(None, "Invalid filter")
